from dataclasses import dataclass
from typing import List, Tuple
import yaml
import os

@dataclass
class DetectionSettings:
    """检测设置参数。
    
    Attributes:
        confidence_threshold (float): 置信度阈值。
        iou_threshold (float): IoU 阈值。
        device (str): 计算设备 (e.g., 'cpu', 'cuda:0')。
        verbose (bool): 是否输出详细信息。
    """
    confidence_threshold: float
    """"置信度阈值"""
    iou_threshold: float
    """"IoU 阈值"""
    device: str
    """"计算设备 (e.g., 'cpu', 'cuda:0')"""
    verbose: bool
    """"是否输出详细信息"""

@dataclass
class LineDetectionSettings:
    """线检测设置参数。
    
    Attributes:
        point_spacing (float): 点间距 (毫米)。
        max_variance (float): 最大方差。
        max_slope (float): 最大斜率。
        sample_step (int): 采样步长。
        distance_weight (float): 距离权重。
        length_weight (float): 长度权重。
        slope_weight (float): 斜率权重。
        width_weight (float): 宽度权重。
        min_width (float): 最小宽度 (毫米)。
        max_width (float): 最大宽度 (毫米)。
    """
    point_spacing: float
    """"点间距 (毫米)"""
    max_variance: float
    """"最大方差"""
    max_slope: float
    """"最大斜率"""
    sample_step: int
    """"采样步长"""
    distance_weight: float
    """"距离权重"""
    length_weight: float
    """"长度权重"""
    slope_weight: float
    """"斜率权重"""
    width_weight: float
    """"宽度权重"""
    min_width: float
    """"最小宽度 (毫米)"""
    max_width: float
    """"最大宽度 (毫米)"""

@dataclass
class CameraTransformation:
    """相机变换参数。
    
    Attributes:
        calib_cam (str): 相机标定文件路径。
        input_shape (Tuple[int, int]): 输入图像尺寸 (宽, 高)。
        output_shape (Tuple[int, int]): 输出图像尺寸 (宽, 高)。
        bev_shape (Tuple[int, int]): BEV 图像尺寸 (宽, 高)。
        bev_pixels_per_mm (float): BEV 每毫米像素数。
        scale_factor (float): 缩放因子。
        cal_inter_param (bool): 是否计算内参。
        mapping_inter (str): 内参映射文件路径。
        mapping_outer (str): 外参映射文件路径。
    """

    calib_cam: str = 'calib_params/left_camera.txt'
    """"相机标定文件路径"""
    input_shape: Tuple[int, int] = (1920, 1080)
    """"输入图像尺寸 (宽, 高)"""
    output_shape: Tuple[int, int] = (640, 384)
    """"输出图像尺寸 (宽, 高)"""
    bev_shape: Tuple[int, int] = (2000, 2000)
    """"BEV 图像尺寸 (宽, 高)"""
    bev_pixels_per_mm: float = 0.3
    """"BEV 每毫米像素数"""
    scale_factor: float = 1.5
    """"缩放因子"""
    cal_inter_param: bool = True
    """"是否计算内参"""
    mapping_inter: str = 'calib_params/inter_map_384x640.npz'
    """"内参映射文件路径"""
    mapping_outer: str = 'calib_params/outer_map_384x640.npz'
    """"外参映射文件路径"""

@dataclass
class CameraSettings:
    """相机设置参数。
    
    Attributes:
        camera_mode (str): 相机模式 ('video' 或 'capture')。
        left_video (str): 左相机视频路径。
        right_video (str): 右相机视频路径。
        left_id (int): 左相机设备ID。
        right_id (int): 右相机设备ID。
        left_calib_video (str): 视频模式左相机标定文件。
        right_calib_video (str): 视频模式右相机标定文件。
        left_calib_cam (str): 采集模式左相机标定文件。
        right_calib_cam (str): 采集模式右相机标定文件。
    """

    camera_mode: str
    """"相机模式 ('video' 或 'capture')"""
    left_video: str
    """"左相机视频路径"""
    right_video: str
    """"右相机视频路径"""
    left_id: int
    """"左相机设备ID"""
    right_id: int
    """"右相机设备ID"""
    left_calib_video: str = 'calib_params/left_camera.txt'
    """"视频模式左相机标定文件"""
    right_calib_video: str = 'calib_params/right_camera.txt'
    """"视频模式右相机标定文件"""
    left_calib_cam: str = 'calib_params/left_camera.txt'
    """"采集模式左相机标定文件"""
    right_calib_cam: str = 'calib_params/right_camera.txt'
    """"采集模式右相机标定文件"""

@dataclass
class Visualization:
    """可视化设置参数。
    
    Attributes:
        output_frame (bool): 是否输出帧图像。
        show_mode (str): 显示模式 ('img', 'bev', 'both')。
        mark_mode (str): 标记模式 ('line', 'point')。
        line_thickness (int): 线条粗细。
        point_size (int): 点大小。
        left_color (Tuple[int]): 左线颜色 [B, G, R]。
        right_color (Tuple[int]): 右线颜色 [B, G, R]。
        center_color (Tuple[int]): 中线颜色 [B, G, R]。
        bev_scale (float): BEV 缩放因子。
    """
    output_frame: bool
    """"是否输出帧图像"""
    show_mode: str
    """"显示模式 ('img', 'bev', 'both')"""
    mark_mode: str
    """"标记模式 ('line', 'point')"""
    line_thickness: int
    """"线条粗细"""
    point_size: int
    """"点大小"""
    left_color: Tuple[int]
    """"左线颜色 [B, G, R]"""
    right_color: Tuple[int]
    """"右线颜色 [B, G, R]"""
    center_color: Tuple[int]
    """"中线颜色 [B, G, R]"""
    bev_scale: float
    """"BEV 缩放因子"""

@dataclass
class LaneDetectionConfig:
    """车道线检测配置。
    
    Attributes:
        model_path (str): 模型路径。
        is_deploy (bool): 是否为部署模式。
        cal_param (bool): 是否使用标定参数。
        camera_lidar_pos (Tuple[float, float]): 相机与激光雷达的相对位置。
        ang_bias (float): 角度偏差。
        left_transform_config (CameraTransformation): 左相机变换配置。
        right_transform_config (CameraTransformation): 右相机变换配置。
        camera (CameraSettings): 相机设置。
        detection (DetectionSettings): 检测设置。
        line_config (LineDetectionSettings): 线检测设置。
        vis_config (Visualization): 可视化设置。
    """
    model_path: str
    """"模型路径"""
    is_deploy: bool
    """"是否为部署模式"""
    cal_param: bool
    """"是否使用标定参数"""
    camera_lidar_pos: Tuple[float, float]
    """"相机与激光雷达的相对位置"""
    ang_bias: float
    """"角度偏差"""
    is_log: bool
    """"是否输出详细时间日志"""
    left_transform_config: CameraTransformation
    """"左相机变换配置"""
    right_transform_config: CameraTransformation
    """"右相机变换配置"""
    camera: CameraSettings
    """"相机设置"""
    detection: DetectionSettings
    """"检测设置"""
    line_config: LineDetectionSettings
    """"线检测设置"""
    vis_config: Visualization
    """"可视化设置"""

    @classmethod
    def from_yaml(cls, file_path: str):
        """从 YAML 文件加载配置。
        
        Args:
            file_path (str): YAML 配置文件路径。
            
        Returns:
            LaneDetectionConfig: 加载的配置对象。
            
        Raises:
            FileNotFoundError: 如果配置文件不存在。
        """
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"配置文件不存在: {file_path}")
        
        with open(file_path, 'r') as f:
            config_data = yaml.safe_load(f)
        
        return cls(
            model_path=config_data.get('model_path', 'models/lane_detection_model.pt'),
            is_deploy=config_data.get('is_deploy', True),
            cal_param=config_data.get('cal_param', True),
            camera_lidar_pos=tuple(config_data.get('camera_lidar_pos', [0.0, 0.0])),
            ang_bias=config_data.get('ang_bias', 5.0),
            is_log=config_data.get('is_log', False),
            left_transform_config=CameraTransformation(**config_data.get('left_transform_config', {})),
            right_transform_config=CameraTransformation(**config_data.get('right_transform_config', {})),
            camera=CameraSettings(**config_data.get('camera', {})),
            detection=DetectionSettings(**config_data.get('detection', {})),
            line_config=LineDetectionSettings(**config_data.get('line_config', {})),
            vis_config=Visualization(**config_data.get('vis_config', {}))
        )
    
    def get_calibration_file(self):
        """根据相机模式获取校准文件路径。
        
        该方法会根据相机模式自动设置正确的校准文件路径。
        """
        if self.camera.camera_mode == 'video':
            self.left_transform_config.calib_cam = self.camera.left_calib_video
            self.right_transform_config.calib_cam = self.camera.right_calib_video
        elif self.camera.camera_mode == 'capture':
            self.left_transform_config.calib_cam = self.camera.left_calib_cam
            self.right_transform_config.calib_cam = self.camera.right_calib_cam
            self.camera.left_video = str(self.camera.left_id)
            self.camera.right_video = str(self.camera.right_id)